use std::{ops::Deref, string, sync::Arc};

use deno_core::{futures::sink, op2, v8, OpState};
use thunderdome::Index;
use QcAudio::core::audio_engine::AudioEngine;
use QcCore::resources::{audio_clip::AudioClip, ResourceManager};
use QcTools::utils::r#ref::Ref;

use crate::utils::GoExt;

#[op2]
pub fn opPlayAudioClip<'a>(
    state: &mut OpState,
    scope: &mut v8::HandleScope<'a>,
    clip: v8::Local<v8::Object>,
) -> v8::Local<'a, v8::Value> {
    let resource_manager = state.borrow::<Arc<ResourceManager>>();

    let audio_engine = state.borrow::<Ref<AudioEngine>>();

    let mut audio_engine = audio_engine.try_write().unwrap();

    let key = v8::String::new(scope, "uuid").unwrap();
    let index = clip.get(scope, key.into()).unwrap();
    let index = v8::Local::<v8::Number>::try_from(index).unwrap();
    let index = index.value() as u64;
    let index = Index::from_bits(index).unwrap();
    let clip = resource_manager
        .get_audio(index)
        .expect("AudioClip 数据已失效！");

    let sink = audio_engine.play(clip.deref().clone());

    if let Ok(sink) = sink {
        let audio = v8::Object::new(scope);

        let index = audio_engine.add_sink(sink);
        let obj = v8::Object::new(scope);
        let key = v8::String::new(scope, "uuid").unwrap();
        let value = v8::Number::new(scope, index.to_bits() as _);
        obj.set(scope, key.into(), value.into());

        GoExt::set_prototype(scope, obj, "Audio");
        return obj.into();
    }

    return v8::undefined(scope).into();
}

#[op2]
pub fn opPlayAudio<'a>(
    state: &mut OpState,
    scope: &mut v8::HandleScope<'a>,
    audio: v8::Local<v8::Object>,
) -> v8::Local<'a, v8::Value> {
    let audio_engine = state.borrow::<Ref<AudioEngine>>();

    let mut audio_engine = audio_engine.try_write().unwrap();

    let key = v8::String::new(scope, "uuid").unwrap();
    let index = audio.get(scope, key.into()).unwrap();
    let index = v8::Local::<v8::Number>::try_from(index).unwrap();
    let index = index.value() as u64;
    let index = Index::from_bits(index).unwrap();

    let sink = audio_engine.get_sink(index).expect("Audio 对象已失效！");

    sink.play();

    return v8::undefined(scope).into();
}

#[op2]
pub fn opPauseAudio<'a>(
    state: &mut OpState,
    scope: &mut v8::HandleScope<'a>,
    audio: v8::Local<v8::Object>,
) -> v8::Local<'a, v8::Value> {
    let audio_engine = state.borrow::<Ref<AudioEngine>>();

    let mut audio_engine = audio_engine.try_write().unwrap();

    let key = v8::String::new(scope, "uuid").unwrap();
    let index = audio.get(scope, key.into()).unwrap();
    let index = v8::Local::<v8::Number>::try_from(index).unwrap();
    let index = index.value() as u64;
    let index = Index::from_bits(index).unwrap();

    let sink = audio_engine.get_sink(index).expect("Audio 对象已失效！");

    sink.pause();

    return v8::undefined(scope).into();
}
